// Attribute.cpp: implementation of the CAttribute class.
//
//////////////////////////////////////////////////////////////////////

#include "mysocket.h"
#include "Attribute.h"
#include "md5.h"
#include <string.h>
#include <malloc.h>
#include "Log.h"
#include "osplatform.h"

#ifdef USE_DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#ifdef SHOW_DEBUG
extern CLog g_Log;
#endif
void TrimLeft(char *p);
void TrimRight(char *s);

#define Align4(n)	(n + (4-n % 4))
#define ATTR_LEN(n)	(n+4)
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CAttribute::CAttribute()
{
	m_nType = 0;
	m_nLength = 0;
}

CAttribute::~CAttribute()
{	
}
/*
#define STUN_ATTRIBUTE_MAPPED_ADDRESS		0x0001 
#define STUN_ATTRIBUTE_RESPONSE_ADDRESS		0x0002
#define STUN_ATTRIBUTE_CHANGE_REQUEST		0x0003
#define STUN_ATTRIBUTE_SOURCE_ADDRESS		0x0004
#define STUN_ATTRIBUTE_CHANGED_ADDRESS		0x0005
#define STUN_ATTRIBUTE_USERNAME				0x0006
#define STUN_ATTRIBUTE_PASSWORD				0x0007
#define STUN_ATTRIBUTE_MESSAGE_INTEGRITY	0x0008
#define STUN_ATTRIBUTE_ERROR_CODE			0x0009
#define STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES	0x000a
#define STUN_ATTRIBUTE_REFLECTED_FROM		0x000b
*/
CMappedAddress::CMappedAddress()
{
	m_nType = STUN_ATTRIBUTE_MAPPED_ADDRESS;
	m_XX = 0;
	m_Family = 0x01;
	m_nPort = 0;
	m_IPV4 = 0;
}
CMappedAddress::CMappedAddress(int family,unsigned long ipv4,unsigned short port)
{
	m_nType = STUN_ATTRIBUTE_MAPPED_ADDRESS;
	m_XX = 0;
	m_Family = family;
	m_nPort = port;
	m_IPV4 = ipv4;
}
#ifdef IPV6_SUPPORT
CMappedAddress::CMappedAddress(int family,struct in6_addr & ipv6,unsigned short port)
{
	m_nType = STUN_ATTRIBUTE_MAPPED_ADDRESS;
	m_XX = 0;
	m_Family = family;
	m_nPort = port;
	m_ipv6 = ipv6;
}
#endif
CMappedAddress::~CMappedAddress()
{
}
int  CMappedAddress::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
#ifndef IPV6_SUPPORT
	*(unsigned short *)p = htons(8);
#else
	if(m_Family == 1)
		*(unsigned short *)p = htons(8);
	else
		*(unsigned short *)p = htons(4 + sizeof(m_ipv6));
#endif
	p+=2;
	n +=2;
	*p++ = 0;
	n++;
	*p++ = m_Family;
	n++;
	*(unsigned short *)p = htons(m_nPort);
	p+=2;
	n+=2;
#ifndef IPV6_SUPPORT
	*(unsigned long *)p = htonl(m_IPV4);
	p+=4;
	n+=4;
#else
	if(m_Family == 1)/* ipv4 */
	{
		*(unsigned long *)p = htonl(m_IPV4);
		p+=4;
		n+=4;
	}else
	{
		*(struct in6_addr *)p = m_ipv6;
		p += sizeof(m_ipv6);
		n += sizeof(m_ipv6);
	}
#endif
#ifndef IPV6_SUPPORT
	in_addr in;
	in.s_addr = htonl(m_IPV4);
	#ifdef SHOW_DEBUG
		if(m_nType == STUN_ATTRIBUTE_MAPPED_ADDRESS)
			g_Log.printf(LOG_MSG,"MappedAddress:%s:%d\r\n",inet_ntoa(in),m_nPort);
		else if(m_nType == STUN_ATTRIBUTE_SOURCE_ADDRESS)
			g_Log.printf(LOG_MSG,"SourceAddress:%s:%d\r\n",inet_ntoa(in),m_nPort);
		else if(m_nType == STUN_ATTRIBUTE_REFLECTED_FROM)
			g_Log.printf(LOG_MSG,"ReflectedFrom:%s:%d\r\n",inet_ntoa(in),m_nPort);
		else if(m_nType == TURN_ATTRIBUTE_ALTERNATE_SERVER)
			g_Log.printf(LOG_MSG,"AlternateServer:%s:%d\r\n",inet_ntoa(in),m_nPort);
	#endif
#else
	const int buflen = 128;
	char buf[buflen+1];
	memset(buf, 0, sizeof(buf));
	if(m_Family == 1)
	{
		in_addr in;
		in.s_addr = htonl(m_IPV4);
		char * p_addr = inet_ntoa(in);
		strncpy(buf, p_addr, buflen);
	}else
	{
		int error;
		struct sockaddr_in6 sockaddr6;
		memset(&sockaddr6, 0, sizeof(sockaddr6));
		sockaddr6.sin6_addr = m_ipv6;
		sockaddr6.sin6_family = AF_INET6;/* ipv6 */
		error = getnameinfo((sockaddr*)&sockaddr6, sizeof(sockaddr6), buf, 128, NULL, 0, NI_NUMERICHOST);
		if(error)
		{
			g_Log.printf(LOG_MSG,"getnameinfo failed in cmappedaddress()\n");
		}
	}
#ifdef SHOW_DEBUG
		if(m_nType == STUN_ATTRIBUTE_MAPPED_ADDRESS)
			g_Log.printf(LOG_MSG,"MappedAddress:%s:%d\r\n",buf,m_nPort);
		else if(m_nType == STUN_ATTRIBUTE_SOURCE_ADDRESS)
			g_Log.printf(LOG_MSG,"SourceAddress:%s:%d\r\n",buf,m_nPort);
		else if(m_nType == STUN_ATTRIBUTE_REFLECTED_FROM)
			g_Log.printf(LOG_MSG,"ReflectedFrom:%s:%d\r\n",buf,m_nPort);
		else if(m_nType == TURN_ATTRIBUTE_ALTERNATE_SERVER)
			g_Log.printf(LOG_MSG,"AlternateServer:%s:%d\r\n",buf,m_nPort);
	#endif
#endif
	return n;
}
int CMappedAddress::Decode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(len < m_nLength + 4)
		return -1;
	p++;
	n++;
	m_Family = *p++;
	n++;
#ifndef IPV6_SUPPORT
	m_nPort = htons(*(unsigned short *)p);
#else
	m_nPort = ntohs(*(unsigned short *)p);

#endif
	p+=2;
	n+=2;

#ifndef IPV6_SUPPORT
	m_IPV4 = htonl(*(unsigned long *)p);
	p+=4;
	n+=4;
	in_addr in;
	in.s_addr = htonl(m_IPV4);
#ifdef SHOW_DEBUG
	if(m_nType == STUN_ATTRIBUTE_MAPPED_ADDRESS)
		g_Log.printf(LOG_MSG,"MappedAddress:%s:%d\r\n",inet_ntoa(in),m_nPort);
	else if(m_nType == STUN_ATTRIBUTE_SOURCE_ADDRESS)
		g_Log.printf(LOG_MSG,"SourceAddress:%s:%d\r\n",inet_ntoa(in),m_nPort);
	else if(m_nType == STUN_ATTRIBUTE_REFLECTED_FROM)
		g_Log.printf(LOG_MSG,"ReflectedFrom:%s:%d\r\n",inet_ntoa(in),m_nPort);
	else if(m_nType == TURN_ATTRIBUTE_ALTERNATE_SERVER)
		g_Log.printf(LOG_MSG,"AlternateServer:%s:%d\r\n",inet_ntoa(in),m_nPort);
  #endif
#else
	const int buflen = 128;
	char buf[buflen+1];
	memset(buf, 0, sizeof(buf));
	if(m_Family == 1)
	{
		m_IPV4 = htonl(*(unsigned long *)p);
		p+=4;
		n+=4;
		in_addr in;
		in.s_addr = htonl(m_IPV4);
		char * p = inet_ntoa(in);
		strncpy(buf, p, buflen);
	}else
	{
		m_ipv6 = *(struct in6_addr *)p;
		p += sizeof(struct in6_addr);
		n += sizeof(struct in6_addr);

		int error;
		struct sockaddr_in6 sockaddr6;
		memset(&sockaddr6, 0, sizeof(sockaddr6));
		sockaddr6.sin6_addr = m_ipv6;
		sockaddr6.sin6_family = AF_INET6;/* ipv6 */
		error = getnameinfo((sockaddr*)&sockaddr6, sizeof(sockaddr6), buf, 128, NULL, 0, NI_NUMERICHOST);
		if(error)
		{
			g_Log.printf(LOG_MSG,"getnameinfo failed in cmappedaddress()\n");
		}		
	}
  #ifdef SHOW_DEBUG
	if(m_nType == STUN_ATTRIBUTE_MAPPED_ADDRESS)
		g_Log.printf(LOG_MSG,"MappedAddress:%s:%d\r\n",buf, m_nPort);
	else if(m_nType == STUN_ATTRIBUTE_SOURCE_ADDRESS)
		g_Log.printf(LOG_MSG,"SourceAddress:%s:%d\r\n",buf, m_nPort);
	else if(m_nType == STUN_ATTRIBUTE_REFLECTED_FROM)
		g_Log.printf(LOG_MSG,"ReflectedFrom:%s:%d\r\n",buf, m_nPort);
	else if(m_nType == TURN_ATTRIBUTE_ALTERNATE_SERVER)
		g_Log.printf(LOG_MSG,"AlternateServer:%s:%d\r\n",buf, m_nPort);
  #endif
#endif
	return n;
}

CRecvChannel::CRecvChannel()
{
	m_nType = MS_ATTRIBUTE_RECV_CHANNEL;
	m_XX = 0;
	m_Family = 0x01;
	m_nPort = 0;
	m_IPV4 = 0;
	m_nChannelID = 0;
}
CRecvChannel::CRecvChannel(int proto,int family,unsigned long ipv4,unsigned short port,unsigned long chid)
{
	m_nType = MS_ATTRIBUTE_RECV_CHANNEL;
	m_XX = proto;
	m_Family = family;
	m_nPort = port;
	m_IPV4 = ipv4;
	m_nChannelID = chid;
}

CRecvChannel::~CRecvChannel()
{
}
int  CRecvChannel::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	*(unsigned short *)p = htons(8);
	p+=2;
	n+=2;
	*p++ = m_XX;
	n++;
	*p++ = m_Family;
	n++;
	*(unsigned short *)p = htons(m_nPort);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_IPV4);
	p+=4;
	n+=4;
	*(unsigned long *)p = htonl(m_nChannelID);
	p+=4;
	n+=4;
	return n;
}
int CRecvChannel::Decode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(len < m_nLength + 4)
		return -1;
	m_XX = *p;
	p++;
	n++;
	m_Family = *p++;
	n++;
	m_nPort = htons(*(unsigned short *)p);
	p+=2;
	n+=2;

	m_IPV4 = htonl(*(unsigned long *)p);
	p+=4;
	n+=4;
	m_nChannelID = htonl(*(unsigned long *)p);
	p+=4;
	n+=4;
	return n;
}



CRelayChannel::CRelayChannel()
{
	m_nType = MS_ATTRIBUTE_RELAY_CHANNEL;
	m_XX = 0;
	m_Family = 0x01;
	m_nPort = 0;
	m_IPV4 = 0;
	m_nChannelID = 0;
	m_nRecvChannelID = 0;
}
CRelayChannel::CRelayChannel(int proto,int family,unsigned long ipv4,unsigned short port,unsigned long rid,unsigned long chid)
{
	m_nType = MS_ATTRIBUTE_RELAY_CHANNEL;
	m_XX = proto;
	m_Family = family;
	m_nPort = port;
	m_IPV4 = ipv4;
	m_nChannelID = chid;
	m_nRecvChannelID = rid;
}

CRelayChannel::~CRelayChannel()
{
}
int  CRelayChannel::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	*(unsigned short *)p = htons(8);
	p+=2;
	n+=2;
	*p++ = m_XX;
	n++;
	*p++ = m_Family;
	n++;
	*(unsigned short *)p = htons(m_nPort);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_IPV4);
	p+=4;
	n+=4;
	*(unsigned long *)p = htonl(m_nChannelID);
	p+=4;
	n+=4;
	*(unsigned long *)p = htonl(m_nRecvChannelID);
	p+=4;
	n+=4;
	return n;
}
int CRelayChannel::Decode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(len < m_nLength + 4)
		return -1;
	m_XX = *p;
	p++;
	n++;
	m_Family = *p++;
	n++;
	m_nPort = htons(*(unsigned short *)p);
	p+=2;
	n+=2;

	m_IPV4 = htonl(*(unsigned long *)p);
	p+=4;
	n+=4;
	m_nChannelID = htonl(*(unsigned long *)p);
	p+=4;
	n+=4;
	m_nRecvChannelID = htonl(*(unsigned long *)p);
	p+=4;
	n+=4;
	return n;
}



CRelayServerID::CRelayServerID()
{
	m_nType = MS_ATTRIBUTE_RELAY_SERVER_ID;
	m_pID = NULL;
}
CRelayServerID::~CRelayServerID()
{
	if(m_pID)
	{
		delete[] m_pID;
		m_pID = NULL;
	}
}

void CRelayServerID::SetRelayServerID(const char *pname)
{
	if(m_pID)
	{
		delete[] m_pID;
		m_pID = NULL;
	}
	if(pname == NULL || strlen(pname) <= 0)
		return;
	m_pID = new char[strlen(pname)+1];
	strcpy(m_pID,pname);
}
int CRelayServerID::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	if(m_pID == NULL)
		return 0;
	m_nLength = strlen(m_pID);
	if(m_nLength%4)
		m_nLength = 4-m_nLength%4 + m_nLength;	

	if(len < 4 + m_nLength)
		return -1;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	memcpy(p,m_pID,strlen(m_pID));
	p+=strlen(m_pID);
	n+=strlen(m_pID);
	for(int i=strlen(m_pID);i<m_nLength;i++)
	{
		*p = '\0';
		p++;
		n++;
	}
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"CRelayServerID = %s\r\n",m_pID);
#endif
	return n;
}
int CRelayServerID::Decode(unsigned char *pdata,int len)
{
	if(m_pID)
	{
		delete[] m_pID;
		m_pID = NULL;
	}
	int n = 0;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength + 4 > len)
		return -1;
	if(m_nLength > 0)
	{
		m_pID = new char[m_nLength+1];
		memcpy(m_pID,p,m_nLength);
		m_pID[m_nLength] = '\0';
		n += m_nLength;
	}
#ifdef SHOW_DEBUG
	if(m_pID)
		g_Log.printf(LOG_MSG,"CRelayServerID = %s\r\n",m_pID);
	else	
		g_Log.printf(LOG_MSG,"CRelayServerID = %s\r\n","NULL");

#endif

	return n;
}

/////////////////////////////////////////////////////////////

CResponseAddress::CResponseAddress()
{
	m_nType = STUN_ATTRIBUTE_RESPONSE_ADDRESS;
	m_XX = 0;
	m_Family = 0x01;
	m_nPort = 0;
	m_IPV4 = 0;
}
CResponseAddress::~CResponseAddress()
{
}
int  CResponseAddress::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	*(unsigned short *)p = htons(8);
	p+=8;
	n +=8;
	*p++ = 0;
	n++;
	*p++ = m_Family;
	n++;
	*(unsigned short *)p = htons(m_nPort);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_IPV4);
	p+=4;
	n+=4;
	in_addr in;
	in.s_addr = htonl(m_IPV4);
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"MappedAddress:%s:%d\r\n",inet_ntoa(in),m_nPort);
#endif
	return n;
}
int CResponseAddress::Decode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(len < m_nLength + 4)
		return -1;
	p++;
	n++;
	m_Family = *p++;
	n++;
	m_nPort = htons(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_IPV4 = htonl(*(unsigned long *)p);
	p+=4;
	n+=4;
	in_addr in;
	in.s_addr = htonl(m_IPV4);
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"MappedAddress:%s:%d\r\n",inet_ntoa(in),m_nPort);
#endif
	return n;
}
/////////////////////////////////////////////////////////

CChangedAddress::CChangedAddress()
{
	m_nType = STUN_ATTRIBUTE_CHANGED_ADDRESS;
	m_XX = 0;
	m_Family = 0x01;
	m_nPort = 0;
	m_IPV4 = 0;
}
CChangedAddress::CChangedAddress(unsigned char family,unsigned long ip,unsigned short port)
{
	m_nType = STUN_ATTRIBUTE_CHANGED_ADDRESS;
	m_XX = 0;
	m_Family = family;
	m_nPort = port;
	m_IPV4 = ip;
}
CChangedAddress::~CChangedAddress()
{
}
int  CChangedAddress::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	*(unsigned short *)p = htons(8);
	p+=2;
	n+=2;
	*p++ = 0;
	n++;
	*p++ = m_Family;
	n++;
	*(unsigned short *)p = htons(m_nPort);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_IPV4);
	p+=4;
	n+=4;
	in_addr in;
	in.s_addr = htonl(m_IPV4);
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"ChangedAddress:Family=%d,ip=%s,port=%d\r\n",m_Family,inet_ntoa(in),m_nPort);
#endif
	return n;
}

int CChangedAddress::Decode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(len < m_nLength + 4)
		return -1;
	p++;
	n++;
	m_Family = *p++;
	n++;
	m_nPort = htons(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_IPV4 = htonl(*(unsigned long *)p);
	p+=4;
	n+=4;
	in_addr in;
	in.s_addr = htonl(m_IPV4);
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"ChangedAddress:Family=%d,ip=%s,port=%d\r\n",m_Family,inet_ntoa(in),m_nPort);
#endif
	return n;
}


CChangeRequest::CChangeRequest()
{
	m_nType = STUN_ATTRIBUTE_CHANGE_REQUEST;
	m_nFlag = 0;
}
CChangeRequest::~CChangeRequest()
{
}
int  CChangeRequest::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	if(len < 8)
		return -1;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = 4;
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nFlag);
	p+=4;
	n+=4;
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"ChangeRequest:ChangeIpFlag=%d,ChangePortFlag=%d\r\n",m_nFlag&ChangeIpFlag,m_nFlag&ChangePortFlag);
#endif
	return n;
	
}
int	CChangeRequest::Decode(unsigned char *pdata,int len)
{
	int n = 0;
	if(len < 8)
		return -1;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != 4)
		return -1;
	m_nFlag = ntohl(*(unsigned long *)p);
	p+=4;
	n+=4;
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"ChangeRequest:ChangeIpFlag=%d,ChangePortFlag=%d\r\n",m_nFlag&ChangeIpFlag,m_nFlag&ChangePortFlag);
#endif
	return n;
}

CUserName::CUserName()
{
	m_nType = STUN_ATTRIBUTE_USERNAME;
	m_pUserName = NULL;
}
CUserName::~CUserName()
{
	if(m_pUserName)
	{
		delete[] m_pUserName;
		m_pUserName = NULL;
	}
}

void CUserName::SetUserName(const char *pname)
{	
	if(m_pUserName)
	{
		delete[] m_pUserName;
		m_pUserName = NULL;
	}
	if(pname == NULL || strlen(pname) <= 0)
		return;
	m_pUserName = new char[strlen(pname)+1];
	strcpy(m_pUserName,pname);
}
int CUserName::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	if(m_pUserName == NULL)
		return 0;

	m_nLength = strlen(m_pUserName);
	if(m_nLength%4)
		m_nLength = 4-m_nLength%4 + m_nLength;
	
	if(len < 4 + m_nLength)
		return -1;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	memcpy(p,m_pUserName,strlen(m_pUserName));
	p+=strlen(m_pUserName);
	n+=strlen(m_pUserName);
	for(int i=strlen(m_pUserName);i<m_nLength;i++)
	{
		*p = '\0';
		p++;
		n++;
	}
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"UserName = %s\r\n",m_pUserName);
#endif
	return n;
}
int CUserName::Decode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength + 4 > len)
		return -1;
	if(m_pUserName)
	{
		delete[] m_pUserName;
		m_pUserName = NULL;
	}
	if(m_nLength > 0)
	{
		m_pUserName = new char[m_nLength+1];
		memset(m_pUserName,0,m_nLength+1);
		memcpy(m_pUserName,p,m_nLength);
	}
#ifdef SHOW_DEBUG
	if(m_pUserName)
		g_Log.printf(LOG_MSG,"UserName = %s\r\n",m_pUserName);
	else
		g_Log.printf(LOG_MSG,"UserName = %s\r\n","NULL");
#endif

	return m_nLength+4;
}


//////////////////////////////////////

CPassword::CPassword()
{
	m_nType = STUN_ATTRIBUTE_PASSWORD;
	m_pPassword = NULL;
}
CPassword::~CPassword()
{
	if(m_pPassword)
	{
		delete[] m_pPassword;
		m_pPassword = NULL;
	}
}

void CPassword::SetPassword(const char *pname)
{
	if(m_pPassword)
	{
		delete[] m_pPassword;
		m_pPassword = NULL;
	}
	if(pname == NULL || strlen(pname) <= 0)
		return;
	m_pPassword = new char[strlen(pname)+1];
	strcpy(m_pPassword,pname);
}
int CPassword::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	if(m_pPassword == NULL)
		return 0;
	m_nLength = strlen(m_pPassword);
	if(m_nLength%4)
		m_nLength = 4-m_nLength%4 + m_nLength;	

	if(len < 4 + m_nLength)
		return -1;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	memcpy(p,m_pPassword,strlen(m_pPassword));
	p+=strlen(m_pPassword);
	n+=strlen(m_pPassword);
	for(int i=strlen(m_pPassword);i<m_nLength;i++)
	{
		*p = '\0';
		p++;
		n++;
	}
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"Password = %s\r\n",m_pPassword);
#endif
	return n;
}
int CPassword::Decode(unsigned char *pdata,int len)
{
	if(m_pPassword)
	{
		delete[] m_pPassword;
		m_pPassword = NULL;
	}
	int n = 0;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength + 4 > len)
		return -1;
	if(m_nLength > 0)
	{
		m_pPassword = new char[m_nLength+1];
		memcpy(m_pPassword,p,m_nLength);
		m_pPassword[m_nLength] = '\0';
		n += m_nLength;
	}
#ifdef SHOW_DEBUG
	if(m_pPassword)
		g_Log.printf(LOG_MSG,"Password = %s\r\n",m_pPassword);
	else	
		g_Log.printf(LOG_MSG,"Password = %s\r\n","NULL");

#endif

	return n;
}
///////////////////////////////////

CChannelID::CChannelID()
{
	m_nType = TURN_ATTRIBUTE_CHANNEL_ID;
	m_pChannelID = NULL;
}
CChannelID::~CChannelID()
{
	if(m_pChannelID)
	{
		delete[] m_pChannelID;
		m_pChannelID = NULL;
	}
}

void CChannelID::SetChannelID(const char *pname)
{	
	if(m_pChannelID)
	{
		delete[] m_pChannelID;
		m_pChannelID = NULL;
	}
	if(pname == NULL || strlen(pname) <= 0)
		return;
	m_pChannelID = new char[strlen(pname)+1];
	strcpy(m_pChannelID,pname);
}
int CChannelID::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	if(m_pChannelID == NULL)
		return 0;

	m_nLength = strlen(m_pChannelID);
	if(m_nLength%4)
		m_nLength = 4-m_nLength%4 + m_nLength;
	
	if(len < 4 + m_nLength)
		return -1;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	memcpy(p,m_pChannelID,strlen(m_pChannelID));
	p+=strlen(m_pChannelID);
	n+=strlen(m_pChannelID);
	for(int i=strlen(m_pChannelID);i<m_nLength;i++)
	{
		*p = '\0';
		p++;
		n++;
	}
#ifdef SHOW_DEBUG
	if(m_pChannelID)
		g_Log.printf(LOG_MSG,"ChannelID = %s\r\n",m_pChannelID);
	else
		g_Log.printf(LOG_MSG,"ChannelID = %s\r\n","NULL");
#endif

	return n;
}
int CChannelID::Decode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength + 4 > len)
		return -1;
	if(m_pChannelID)
	{
		delete[] m_pChannelID;
		m_pChannelID = NULL;
	}
	if(m_nLength > 0)
	{
		m_pChannelID = new char[m_nLength+1];
		memset(m_pChannelID,0,m_nLength+1);
		memcpy(m_pChannelID,p,m_nLength);
	}
#ifdef SHOW_DEBUG
	if(m_pChannelID)
		g_Log.printf(LOG_MSG,"ChannelID = %s\r\n",m_pChannelID);
	else
		g_Log.printf(LOG_MSG,"ChannelID = %s\r\n","NULL");
#endif


	return m_nLength+4;
}


CMessageIntegrity::CMessageIntegrity()
{
	m_nType = STUN_ATTRIBUTE_MESSAGE_INTEGRITY;
	m_pDigest = NULL;
	m_nLength = 0;
}
CMessageIntegrity::~CMessageIntegrity()
{
	if(m_pDigest)
		delete[] m_pDigest;
}
void CMessageIntegrity::SetData(const char *pdata,int len)
{
	if(m_pDigest)
		delete[] m_pDigest;
	m_pDigest = new char[len+1];
	memcpy(m_pDigest,pdata,len);
	m_pDigest[len] = '\0';
	m_nLength = len;
}
int CMessageIntegrity::Encode(unsigned char *pdata,int len)
{
	int i;
	int n = 0;
	unsigned char *p = pdata;	
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	int l;
	if(m_nLength%4)
		l = 4-m_nLength%4 + m_nLength;
	else
		l = m_nLength;
	*(unsigned short *)p = htons(l);
	p+=2;
	n+=2;
	memcpy(p,m_pDigest,m_nLength);
	p+=m_nLength;
	for(i=m_nLength;i<l;i++)
		*p++ = '\0';
	n+= l;

#ifdef SHOW_DEBUG
	char buf[128];
	for(i=0;i<l;i++)
	{
		sprintf(&buf[2*i],"%x",(unsigned char )m_pDigest[i]);
	}
	g_Log.printf(LOG_MSG,"Digest = %s\r\n",buf);
#endif
	return n;
}
int CMessageIntegrity::Decode(unsigned char *pdata,int len)
{
	if(m_pDigest)
	{
		delete[] m_pDigest;
		m_pDigest = NULL;
	}
	int n = 0;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength + 4 > len)
		return -1;
	m_pDigest = new char[m_nLength+1];
	memcpy(m_pDigest,p,m_nLength);
	m_pDigest[m_nLength] = '\0';
	n += m_nLength;
#ifdef SHOW_DEBUG
	char buf[128];
	for(int i=0;i<m_nLength;i++)
	{
		sprintf(&buf[2*i],"%x",(unsigned char )m_pDigest[i]);
	}
	g_Log.printf(LOG_MSG,"Digest = %s\r\n",buf);
#endif

	return n;
}
CErrorCode::CErrorCode()
{
	m_nType = STUN_ATTRIBUTE_ERROR_CODE;
	m_nClass = 0;
	m_nNumber = 0;
	m_pReason = NULL;
}
CErrorCode::CErrorCode(int errorcode)
{
	m_nType = STUN_ATTRIBUTE_ERROR_CODE;
	m_nClass = errorcode/100;
	m_nNumber = errorcode%100;
	m_pReason = NULL;
}
CErrorCode::~CErrorCode()
{
	if(m_pReason)
	{
		delete[] m_pReason;
		m_pReason = NULL;
	}
}
void CErrorCode::SetErrorCode(int code)
{
	m_nClass = code/100;
	m_nNumber = code%100;
}

int CErrorCode::GetErrorCode()
{
	int code = m_nClass*100+m_nNumber;
	return code;
}

void CErrorCode::SetReason(const char *pres)
{
	if(m_pReason)
	{
		delete[] m_pReason;
		m_pReason = NULL;
	}
	if(pres && strlen(pres) > 0)
	{
		m_pReason = new char[strlen(pres)+1];
		strcpy(m_pReason,pres);
	}
}
int CErrorCode::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	if(m_pReason)
	{
		if(strlen(m_pReason)%4)
			m_nLength = 4 + strlen(m_pReason) + (4 - strlen(m_pReason)%4);
		else
			m_nLength = 4 + strlen(m_pReason);
	}
	else
		m_nLength = 4;
	if(pdata == NULL || len < m_nLength)
		return -1;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl((m_nClass << 21) | (m_nNumber << 24));
	p+=4;
	n+=4;
	if(m_pReason)
	{
		memcpy(p,m_pReason,strlen(m_pReason));
		p+=strlen(m_pReason);
		n+=strlen(m_pReason);
		for(int i=n;i<m_nLength + 4;i++)
		{
			*p++ = '\0';
			n++;
		}
	}
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"Reason = %s\r\n",m_pReason);	
#endif

	return n;
}
int CErrorCode::Decode(unsigned char *pdata,int len)
{
	int n = 0;
	
	if(pdata == NULL || len < 4)
		return -1;
	unsigned char *p = pdata;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	if(len < m_nLength + 2)
		return -1;
	unsigned long l = ntohl(*(unsigned long *)p);
	p+=4;
	m_nClass = (l >> 21) & 0x07;
	m_nNumber = (l >> 24)&0xff;
	n = m_nLength - 4;
	if(m_pReason)
	{
		delete[] m_pReason;
		m_pReason = NULL;
	}
	if(n > 0)
	{
		
		m_pReason = new char[n+1];
		memset(m_pReason,0,n+1);
		memcpy(m_pReason,p,n);		
	}	
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"ErrorCode:%d\r\n",m_nClass*100 + m_nNumber);
#endif
	return m_nLength + 4;
}
CUnknownAttributes::CUnknownAttributes()
{
	m_nType = STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES;
	m_pAttributes = NULL;
	m_nNumber = 0;
}
CUnknownAttributes::~CUnknownAttributes()
{
	if(m_pAttributes)
	{
		free(m_pAttributes);
		m_pAttributes = NULL;
	}
}
void CUnknownAttributes::AddAttribute(unsigned short attrib)
{
	if(m_pAttributes)
	{
		m_pAttributes = (unsigned short*)realloc(m_pAttributes,sizeof(short)*(m_nNumber+1));
	}
	else
		m_pAttributes = (unsigned short *)malloc(sizeof(short));
	m_pAttributes[m_nNumber] = attrib;
	m_nNumber++;
}

int	CUnknownAttributes::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = 2*m_nNumber;
	if(m_nLength % 4)
	{
		m_nLength += (4 - m_nLength%4);
	}
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	memset(p,0,m_nLength);
	for(int i=0;i<m_nNumber;i++)
	{
		*(unsigned short *)p = htons(m_pAttributes[i]);
		p+=2;
		n+=2;
	}
	return m_nLength + 4;
}
int CUnknownAttributes::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_pAttributes)
	{
		free(m_pAttributes);
		m_pAttributes = NULL;
	}
	m_nNumber = 0;
	if(m_nLength > 0)
	{
		m_pAttributes = (unsigned short *)malloc(m_nLength);
		for(int i=0;i<m_nLength/2;i++)
		{
			m_pAttributes[i] = ntohs(*(unsigned short *)p);
			p+=2;
			n+=2;
		}
	}
	return m_nLength + 4;
}

CLifeTime::CLifeTime()
{
	m_nType = TURN_ATTRIBUTE_LIFETIME;
	m_nLifeTime = 0;	
}
CLifeTime::~CLifeTime()
{	
}

int	CLifeTime::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nLifeTime);
	return m_nLength + 4;
}
int CLifeTime::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nLifeTime = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}


CStartTime::CStartTime()
{
	m_nType = TURN_ATTRIBUTE_START_TIME;
	m_nStartTime = 0;	
}
CStartTime::~CStartTime()
{	
}

int	CStartTime::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nStartTime);
	return m_nLength + 4;
}
int CStartTime::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nStartTime = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}








CStopTime::CStopTime()
{
	m_nType = TURN_ATTRIBUTE_STOP_TIME;
	m_nStopTime = 0;	
}
CStopTime::~CStopTime()
{	
}

int	CStopTime::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nStopTime);
	return m_nLength + 4;
}
int CStopTime::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nStopTime = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}

//////////////////////////////////////////////////////////////////

int	CMagicCookie::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nMagicCookie);
	return m_nLength + 4;
}
int CMagicCookie::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nMagicCookie = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}

/////////////////////////////////////////////////////
CBandwidth::CBandwidth()
{
	m_nType = TURN_ATTRIBUTE_BANDWIDTH;
	m_nBandwidth = 0;	
}
CBandwidth::~CBandwidth()
{	
}

int	CBandwidth::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nBandwidth);
	return m_nLength + 4;
}
int CBandwidth::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nBandwidth = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}


int	CNonce::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	int le;
	if(m_lpszNonce == NULL)
		le = m_nLength = 0;
	else
	{
		le = strlen(m_lpszNonce);
		m_nLength = 4*((le+3)/4);
	}
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	
	for(n=0;n<m_nLength;n++)
	{
		if(n < le)
			*p++ = m_lpszNonce[n];
		else
			*p++ = ' ';
	}
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"Nonce = %s\r\n",m_lpszNonce);	
#endif

	return m_nLength + 4;
}
int CNonce::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_lpszNonce)
	{
		delete[] m_lpszNonce;
		m_lpszNonce = NULL;
	}
	if(m_nLength > 0)
	{
		m_lpszNonce = new char[m_nLength + 1];
		for(n=0;n<m_nLength;n++)
		{
			m_lpszNonce[n] = *p++;
		}
		m_lpszNonce[m_nLength] = '\0';
		TrimRight(m_lpszNonce);
	}
#ifdef SHOW_DEBUG
	if(m_lpszNonce)
		g_Log.printf(LOG_MSG,"Nonce = %s\r\n",m_lpszNonce);	
	else
		g_Log.printf(LOG_MSG,"Nonce = %s\r\n","NULL");	
#endif

	return m_nLength + 4;
}



int	CRealm::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	int le;
	if(m_lpszRealm == NULL)
		le = m_nLength = 0;
	else
	{
		le = strlen(m_lpszRealm);
		m_nLength = 4*((le+3)/4);
	}
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	
	for(n=0;n<m_nLength;n++)
	{
		if(n < le)
			*p++ = m_lpszRealm[n];
		else
			*p++ = ' ';
	}
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"Realm = %s\r\n",m_lpszRealm);	
#endif
	return m_nLength + 4;
}
int CRealm::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_lpszRealm)
	{
		delete[] m_lpszRealm;
		m_lpszRealm = NULL;
	}
	if(m_nLength > 0)
	{
		m_lpszRealm = new char[m_nLength + 1];
		for(n=0;n<m_nLength;n++)
		{
			m_lpszRealm[n] = *p++;
		}
		m_lpszRealm[m_nLength] = '\0';
		TrimRight(m_lpszRealm);
	}
#ifdef SHOW_DEBUG
	if(m_lpszRealm)
		g_Log.printf(LOG_MSG,"Realm = %s\r\n",m_lpszRealm);	
	else
		g_Log.printf(LOG_MSG,"Realm = %s\r\n","NULL");	

#endif

	return m_nLength + 4;
}


CData::CData()
{
	m_pData = NULL;
	m_nLength = 0;
	m_nType = TURN_ATTRIBUTE_DATA;
}
CData::CData(const char *pdata,int len)
{
	if(pdata && len > 0)
	{
		m_pData = new char[len];
		memcpy(m_pData,pdata,len);
		m_nLength = len;
	}
	else
	{
		m_nLength = 0;
		m_pData = NULL;
	}
	m_nType = TURN_ATTRIBUTE_DATA;
}
CData::~CData()
{
	if(m_pData)
	{
		delete[] m_pData;
		m_pData = NULL;
	}
	m_nLength = 0;
}
int CData::Encode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	
	memcpy(p,m_pData,m_nLength);
//	p+= m_nLength;
	return m_nLength + 4;
}

int CData::Decode(unsigned char *pdata,int len)
{
	if(m_pData)
	{
		delete[] m_pData;
		m_pData = NULL;
	}
	m_nLength = 0;
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;	
	if(m_nLength > 0)
	{
		m_pData = new char[m_nLength];
		memcpy(m_pData,p,m_nLength);
	}
	return m_nLength + 4;
}
bool CData::SetData(const char *pdata,int len)
{
	if(m_pData)
	{
		delete[] m_pData;
		m_pData = NULL;
	}
	m_nLength = 0;
	if(pdata && len > 0)
	{
		m_pData = new char[len];
		memcpy(m_pData,pdata,len);
		m_nLength = len;
	}
	return true;
}


CVideowidth::CVideowidth()
{
	m_nType = TURN_ATTRIBUTE_VIDEO_WIDTH;
	m_nVideowidth = 0;	
}
CVideowidth::~CVideowidth()
{	
}

int	CVideowidth::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nVideowidth);
	return m_nLength + 4;
}
int CVideowidth::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nVideowidth = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}



CVideoheight::CVideoheight()
{
	m_nType = TURN_ATTRIBUTE_VIDEO_HEIGHT;
	m_nVideoheight = 0;	
}
CVideoheight::~CVideoheight()
{	
}

int	CVideoheight::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nVideoheight);
	return m_nLength + 4;
}
int CVideoheight::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nVideoheight = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}




CVideoformat::CVideoformat()
{
	m_nType = TURN_ATTRIBUTE_VIDEO_FORMAT;
	m_nVideoformat = 0;	
}
CVideoformat::~CVideoformat()
{	
}

int	CVideoformat::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nVideoformat);
	return m_nLength + 4;
}
int CVideoformat::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nVideoformat = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}





CVideoframerate::CVideoframerate()
{
	m_nType = TURN_ATTRIBUTE_VIDEO_FRAMERATE;
	m_nVideoframerate = 0;	
}
CVideoframerate::~CVideoframerate()
{	
}

int	CVideoframerate::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nVideoframerate);
	return m_nLength + 4;
}
int CVideoframerate::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nVideoframerate = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}


CRecordID::CRecordID()
{
	m_nType = TURN_ATTRIBUTE_RECORD_ID;
	m_pRecordID = 0;	
}
CRecordID::~CRecordID()
{	
	if(m_pRecordID)
	{
		delete[] m_pRecordID;
		m_pRecordID = NULL;
	}
}

int	CRecordID::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	int le;
	if(m_pRecordID == NULL)
		le = m_nLength = 0;
	else
	{
		le = strlen(m_pRecordID);
		m_nLength = 4*((le+3)/4);
	}
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	
	for(n=0;n<m_nLength;n++)
	{
		if(n < le)
			*p++ = m_pRecordID[n];
		else
			*p++ = ' ';
	}
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"RecordID = %s\r\n",m_pRecordID);	
#endif
	return m_nLength + 4;
}
int CRecordID::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_pRecordID)
	{
		delete[] m_pRecordID;
		m_pRecordID = NULL;
	}
	if(m_nLength > 0)
	{
		m_pRecordID = new char[m_nLength + 1];
		for(n=0;n<m_nLength;n++)
		{
			m_pRecordID[n] = *p++;
		}
		m_pRecordID[m_nLength] = '\0';
		TrimRight(m_pRecordID);
	}
#ifdef SHOW_DEBUG
	if(m_pRecordID)
		g_Log.printf(LOG_MSG,"RecordID = %s\r\n",m_pRecordID);	
	else
		g_Log.printf(LOG_MSG,"RecordID = %s\r\n","NULL");	
#endif
	return m_nLength + 4;
}

// added by liuhf 2007.10.10


CPlayScale::CPlayScale()
{
	m_nType = TURN_ATTRIBUTE_PLAY_SCALE;
	m_nPlayScale = 0;	
}

CPlayScale::~CPlayScale()
{	
}

int	CPlayScale::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nPlayScale);
	return m_nLength + 4;
}

int CPlayScale::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nPlayScale = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}


CPlayType::CPlayType()
{
	m_nType = TURN_ATTRIBUTE_PLAY_TYPE;
	m_pPlayType = NULL;	
}

CPlayType::~CPlayType()
{	
	if(m_pPlayType)
	{
		delete[] m_pPlayType;
		m_pPlayType = NULL;
	}
}

int	CPlayType::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	int le;
	if(m_pPlayType == NULL)
		le = m_nLength = 0;
	else
	{
		le = strlen(m_pPlayType);
		m_nLength = 4*((le+3)/4);
	}
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	
	for(n=0;n<m_nLength;n++)
	{
		if(n < le)
			*p++ = m_pPlayType[n];
		else
			*p++ = ' ';
	}
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"PlayType = %s\r\n",m_pPlayType);	
#endif
	return m_nLength + 4;
}
int CPlayType::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_pPlayType)
	{
		delete[] m_pPlayType;
		m_pPlayType = NULL;
	}
	if(m_nLength > 0)
	{
		m_pPlayType = new char[m_nLength + 1];
		for(n=0;n<m_nLength;n++)
		{
			m_pPlayType[n] = *p++;
		}
		m_pPlayType[m_nLength] = '\0';
		TrimRight(m_pPlayType);
	}
#ifdef SHOW_DEBUG
	if(m_pPlayType)
		g_Log.printf(LOG_MSG,"PlayType = %s\r\n",m_pPlayType);	
	else
		g_Log.printf(LOG_MSG,"PlayType = %s\r\n","NULL");	
#endif
	return m_nLength + 4;
}


void CPlayType::SetPlayType(const char *ptype)
{	
	if(m_pPlayType)
	{
		delete[] m_pPlayType;
		m_pPlayType = NULL;
	}
	if(ptype == NULL || strlen(ptype) <= 0)
		return;
	m_pPlayType = new char[strlen(ptype)+1];
	strcpy(m_pPlayType, ptype);
}
  
// added by liuhf 2007.10.10



COwnerID::COwnerID()
{
	m_nType = TURN_ATTRIBUTE_OWNER_ID;
	m_pOwnerID = 0;	
}
COwnerID::~COwnerID()
{	
	if(m_pOwnerID)
	{
		delete[] m_pOwnerID;
		m_pOwnerID = NULL;
	}
}

int	COwnerID::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	int le;
	if(m_pOwnerID == NULL)
		le = m_nLength = 0;
	else
	{
		le = strlen(m_pOwnerID);
		m_nLength = 4*((le+3)/4);
	}
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	
	for(n=0;n<m_nLength;n++)
	{
		if(n < le)
			*p++ = m_pOwnerID[n];
		else
			*p++ = ' ';
	}
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"OwnerID = %s\r\n",m_pOwnerID);	
#endif
	return m_nLength + 4;
}
int COwnerID::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_pOwnerID)
	{
		delete[] m_pOwnerID;
		m_pOwnerID = NULL;
	}
	if(m_nLength > 0)
	{
		m_pOwnerID = new char[m_nLength + 1];
		for(n=0;n<m_nLength;n++)
		{
			m_pOwnerID[n] = *p++;
		}
		m_pOwnerID[m_nLength] = '\0';
		TrimRight(m_pOwnerID);
	}
#ifdef SHOW_DEBUG
	if(m_pOwnerID)
		g_Log.printf(LOG_MSG,"OwnerID = %s\r\n",m_pOwnerID);	
	else
		g_Log.printf(LOG_MSG,"OwnerID = %s\r\n","NULL");	
#endif
	return m_nLength + 4;
}



CSubTitle::CSubTitle()
{
	m_nType = TURN_ATTRIBUTE_SUBTITLE;
	m_pSubTitle = 0;	
}
CSubTitle::~CSubTitle()
{	
	if(m_pSubTitle)
	{
		delete[] m_pSubTitle;
		m_pSubTitle = NULL;
	}
}

int	CSubTitle::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	int le;
	if(m_pSubTitle == NULL)
		le = m_nLength = 0;
	else
	{
		le = strlen(m_pSubTitle);
		m_nLength = 4*((le+3)/4);
	}
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	
	for(n=0;n<m_nLength;n++)
	{
		if(n < le)
			*p++ = m_pSubTitle[n];
		else
			*p++ = ' ';
	}
#ifdef SHOW_DEBUG
	g_Log.printf(LOG_MSG,"SubTitle = %s\r\n",m_pSubTitle);	
#endif
	return m_nLength + 4;
}
int CSubTitle::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_pSubTitle)
	{
		delete[] m_pSubTitle;
		m_pSubTitle = NULL;
	}
	if(m_nLength > 0)
	{
		m_pSubTitle = new char[m_nLength + 1];
		for(n=0;n<m_nLength;n++)
		{
			m_pSubTitle[n] = *p++;
		}
		m_pSubTitle[m_nLength] = '\0';
		TrimRight(m_pSubTitle);
	}
#ifdef SHOW_DEBUG
	if(m_pSubTitle)
		g_Log.printf(LOG_MSG,"SubTitle = %s\r\n",m_pSubTitle);	
	else
		g_Log.printf(LOG_MSG,"SubTitle = %s\r\n","NULL");	
#endif
	return m_nLength + 4;
}



CSubTitlePos::CSubTitlePos()
{
	m_nType = TURN_ATTRIBUTE_SUBTITLE_POS;
	m_nSubTitlePos = 0;	
}
CSubTitlePos::~CSubTitlePos()
{	
}

int	CSubTitlePos::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nSubTitlePos);
	return m_nLength + 4;
}
int CSubTitlePos::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nSubTitlePos = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}




CTimeTitlePos::CTimeTitlePos()
{
	m_nType = TURN_ATTRIBUTE_TIMETITLE_POS;
	m_nTimeTitlePos = 0;	
}
CTimeTitlePos::~CTimeTitlePos()
{	
}

int	CTimeTitlePos::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nTimeTitlePos);
	return m_nLength + 4;
}
int CTimeTitlePos::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength != sizeof(long))
		return -1;
	m_nTimeTitlePos = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}

#ifdef _EHOME_
//////////////////////////////////////////////////////////////////////////
// Stone Whoo add the following code to implement the extended TURN attributes
//////////////////////////////////////////////////////////////////////////
int CKeepAliveExpire::Encode(unsigned char *pdata,int len)
{
	if(len < (m_nLength+4))
		return -1;

	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nExpire);

	return m_nLength + 4;
}


int CKeepAliveExpire::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	
	if(m_nLength != sizeof(m_nExpire) 
		|| len<ATTR_LEN(m_nLength))
		return -1;

	m_nExpire = ntohl(*(unsigned long *)p);

	return m_nLength + 4;
}

int CMaxConnNum::Encode(unsigned char *pdata,int len)
{
	if(len < (m_nLength+4))
		return -1;

	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nMaxConnNum);

	return m_nLength + 4;
}

int CMaxConnNum::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	
	if(m_nLength != sizeof(m_nMaxConnNum) 
		|| len<ATTR_LEN(m_nLength))
		return -1;

	m_nMaxConnNum = ntohl(*(unsigned long *)p);

	return m_nLength + 4;
}

void CEncryptedUserName::SetUserName(const unsigned char *pname, int len)
{
	if(len && pname)
	{
		m_nLength = Align4(len);
		
		if(m_pEncryptedUserName)
			delete []m_pEncryptedUserName;

		m_pEncryptedUserName = new unsigned char[m_nLength];
		memcpy(m_pEncryptedUserName, pname, len);
		
		if(m_nLength > len)
		{
			memset(m_pEncryptedUserName+len, 0, m_nLength-len);
		}
	}
}

int CEncryptedUserName::Encode(unsigned char *pdata,int len)
{
	if(len < (m_nLength+4))
		return -1;	// buffer is too small!

	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;

	if(0 == m_nLength && m_pEncryptedUserName)
	{
		delete []m_pEncryptedUserName;
		m_pEncryptedUserName = 0;
	}
	else if(m_nLength > 0 && m_pEncryptedUserName)
	{
		memcpy(p, m_pEncryptedUserName, m_nLength);
		p+=m_nLength;
		n+=m_nLength;
	}
	
	return m_nLength + 4;
}


int CEncryptedUserName::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);

	if(m_nLength%4 || m_nLength+4 > len)
		return -1;

	p+=2;
	n+=2;

	if(m_pEncryptedUserName)
	{
		delete []m_pEncryptedUserName;
		m_pEncryptedUserName = 0;
	}

	if(m_nLength > 0)
	{
		m_pEncryptedUserName = new unsigned char[m_nLength];
		memcpy(m_pEncryptedUserName, p, m_nLength);
	}

	return m_nLength + 4;
}

void CEncryptedPassword::SetPassword(const unsigned char *ppassword, int len)
{
	if(len && ppassword)
	{
		m_nLength = Align4(len);
		
		if(m_pEncryptedPassword)
			delete []m_pEncryptedPassword;

		m_pEncryptedPassword = new unsigned char[m_nLength];
		memcpy(m_pEncryptedPassword, ppassword, len);
		
		if(m_nLength > len)
		{
			memset(m_pEncryptedPassword+len, 0, m_nLength-len);
		}
	}
}

int CEncryptedPassword::Encode(unsigned char *pdata,int len)
{
	if(len < (m_nLength+4))
		return -1;	// buffer is too small!

	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;

	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;

	if(0 == m_nLength && m_pEncryptedPassword)
	{
		delete []m_pEncryptedPassword;
		m_pEncryptedPassword = 0;
	}
	else if(m_nLength > 0 && m_pEncryptedPassword)
	{
		memcpy(p, m_pEncryptedPassword, m_nLength);
		p+=m_nLength;
		n+=m_nLength;
	}
	
	return m_nLength + 4;
}


int CEncryptedPassword::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);

	if(m_nLength%4 || m_nLength+4 > len)
		return -1;

	p+=2;
	n+=2;

	if(m_pEncryptedPassword)
	{
		delete []m_pEncryptedPassword;
		m_pEncryptedPassword = 0;
	}

	if(m_nLength > 0)
	{
		m_pEncryptedPassword = new unsigned char[m_nLength];
		memcpy(m_pEncryptedPassword, p, m_nLength);
	}

	return m_nLength + 4;
}

int CRecvChannelID::Encode(unsigned char *pdata,int len)
{
	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	
	*(unsigned long*)p = htonl(m_chann);

	return m_nLength + 4;
}

int CRecvChannelID::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if((m_nLength && m_nLength != sizeof(m_chann))
		 || len<ATTR_LEN(m_nLength))
		return -1;

	if(m_nLength)
		m_chann = ntohl(*(unsigned long*)p);
	else
		m_chann = 0;

	return m_nLength + 4;
}

void CSessionID::SetSessionID(std::string& sessionid)
{
	int len = sessionid.size();
	if(len)
	{
		m_nLength = Align4(len);
		m_sSessionID = sessionid;
	}
}

int CSessionID::Encode(unsigned char *pdata,int len)
{
	if(len < (m_nLength+4))
		return -1;	// buffer is too small!

	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;

	if(0 != m_nLength)
	{
		int nsize = m_sSessionID.size();
		memcpy(p, m_sSessionID.c_str(), nsize);

		if(m_nLength > nsize)		// appending 0!
			memset(p+nsize, 0, m_nLength - nsize);

		p+=m_nLength;
		n+=m_nLength;
	}
	
	return m_nLength + 4;
}

int CSessionID::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);

	if(m_nLength%4 || m_nLength+4 > len)
		return -1;

	p+=2;
	n+=2;

	if(m_nLength > 0)
	{
		char sess[1024];
		
		if(len < 1024)
		{
			memcpy(sess, pdata, len);
			sess[len] = 0;
			m_sSessionID = sess;
		}
		else
		{
			char* tmp = new char[len+1];

			memcpy(tmp, pdata, len);
			tmp[len] = 0;

			m_sSessionID = tmp;
			delete []tmp;
		}
	}

	return m_nLength + 4;
}

int CRecvPortID::Encode(unsigned char *pdata,int len)
{
	if(len < (m_nLength+4))
		return -1;

	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	
	if(!m_nLength || !m_nPort)
	{
		m_nLength = 0;
		m_nPort = 0;
	}

	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;

	if(m_nLength)
		*(int32*)p = htonl(m_nPort);

	return m_nLength + 4;
}

int CRecvPortID::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	
	if((m_nLength && (m_nLength != sizeof(m_nPort)))
		 || len<ATTR_LEN(m_nLength))
		return -1;

	if(m_nLength)
		m_nPort = ntohl(*(int32*)p);
	else
		m_nPort = 0;

	return m_nLength + 4;
}

CRecvChannAttrs::CRecvChannAttrs()
{
	m_pRecvProtoType = 0;
	m_pRecvChannID = 0;
	m_pRecvAllocatedAddr = 0;	
	m_pRecvSessionID = 0;
	m_pRecvChannSrcAddr = 0;
}

CRecvChannAttrs::CRecvChannAttrs(CProtocolType* pProtoType, CRecvChannelID* pChannID, 
								CAllocatedAddress* pAllocateAddr, CSessionID* pSessionID, 
								CChannSrcAddress* pSrcAddr)
{
	m_pRecvProtoType = pProtoType;
	m_pRecvChannID = pChannID;
	m_pRecvAllocatedAddr = pAllocateAddr;	
	m_pRecvSessionID = pSessionID;
	m_pRecvChannSrcAddr = pSrcAddr;
}

CRecvChannAttrs::~CRecvChannAttrs()
{
	Clear();
}

void CRecvChannAttrs::Clear()
{	
	if(m_pRecvAllocatedAddr)
	{
		delete m_pRecvAllocatedAddr;
		m_pRecvAllocatedAddr = 0;
	}
	if(m_pRecvChannID)
	{
		delete m_pRecvChannID;
		m_pRecvChannID = 0;
	}
	if(m_pRecvChannSrcAddr)
	{
		delete m_pRecvChannSrcAddr;
		m_pRecvChannSrcAddr = 0;
	}
	if(m_pRecvSessionID)
	{
		delete m_pRecvSessionID;
		m_pRecvSessionID = 0;
	}
	if(m_pRecvProtoType)
	{
		delete m_pRecvProtoType;
		m_pRecvProtoType = 0;
	}
}

int CRecvChannAttrs::Encode(unsigned char *pdata, int len)
{
	// test if all attrs are valid!
	if(!m_pRecvProtoType || !m_pRecvChannID || !m_pRecvAllocatedAddr
		|| !m_pRecvSessionID || !m_pRecvChannSrcAddr)
	{
		Clear();
		return 0;
	}

	int nRet = 0;
	unsigned char *p = pdata;

	// append prototype
	nRet = m_pRecvProtoType->Encode(p, len);
	if(nRet <= 0)
	{
		return 0;
	}
	p += nRet;
	
	// allocated addr
	nRet = m_pRecvChannID->Encode(p, len);
	if(nRet <= 0)
	{
		return 0;
	}
	p += nRet;

	nRet = m_pRecvAllocatedAddr->Encode(p, len);
	if(nRet <= 0)
	{
		return 0;
	}
	p += nRet;

	nRet = m_pRecvSessionID->Encode(p, len);
	if(nRet <= 0)
	{
		return 0;
	}
	p += nRet;

	nRet = m_pRecvChannSrcAddr->Encode(p, len);
	if(nRet <= 0)
	{
		return 0;
	}
	p += nRet;

	return (p-pdata);
}

int CRecvChannAttrs::Decode(unsigned char *pdata,int len)
{
	Clear();
	
	unsigned char *p = pdata;
	int n = len, nRet = 0;
	uint16 nAttrType = ntohs(*(unsigned short *)p), nAttrLen;
	
	if(MS_ATTRIBUTE_PROTO_TYPE != nAttrType)
		return 0;

	m_pRecvProtoType = new CProtocolType();
	nRet = m_pRecvProtoType->Decode(pdata, len);
	if(nRet <= 0)
		return 0;
	n -= nRet;
	p += nRet;

	while(n > 0)
	{
		nAttrType = ntohs(*(unsigned short *)p);
		p+=2;
		n-=2;

		nAttrLen = ntohs(*(unsigned short *)p);
		p+=2;
		n-=2;

		if(nAttrLen%4 || nAttrLen > n)
			return 0;

		p-=4;
		n+=4;
		switch(nAttrType)
		{			
		case MS_ATTRIBUTE_RECV_CHANNEL_ID:
			{
				m_pRecvChannID = new CRecvChannelID;
				nRet = m_pRecvChannID->Decode(p,n);
				if(nRet == -1)
					return 0;

				p+=nRet;
				n-=nRet;
			}
			break;
		case MS_ATTRIBUTE_ADDRESS:
			{
				m_pRecvAllocatedAddr = new CAllocatedAddress;
				nRet = m_pRecvAllocatedAddr->Decode(p,n);
				if(nRet == -1)
					return 0;
				
				p+=nRet;
				n-=nRet;
			}
			break;
		case MS_ATTRIBUTE_SESSION_ID:
			{
				m_pRecvSessionID = new CSessionID;
				nRet = m_pRecvSessionID->Decode(p,n);
				if(nRet == -1)
					return 0;
				
				p +=nRet;
				n -=nRet;
			}
			break;
		case MS_ATTRIBUTE_SOURCE_ADDRESS:
			{
				m_pRecvChannSrcAddr = new CChannSrcAddress;
				nRet = m_pRecvChannSrcAddr->Decode(p,n);
				if(nRet == -1)
					return 0;
				
				p+=nRet;
				n-=nRet;
			}
			break;
			
		default:
			{//
				//printf("error type\n");
				p+=(nAttrLen+4);
				n-=(nAttrLen+4);
			}
			break;
		}

		if(m_pRecvProtoType && m_pRecvChannID && m_pRecvAllocatedAddr
		&& m_pRecvSessionID && m_pRecvChannSrcAddr)
		{
			break;
		}
	}

	if(!m_pRecvProtoType || !m_pRecvChannID || !m_pRecvAllocatedAddr
		|| !m_pRecvSessionID || !m_pRecvChannSrcAddr)
	{
		Clear();
		return 0;
	}

	return (p-pdata);
}

void CRecvChannAttrs::SetRecvSrcAddr(CChannSrcAddress* pSrcAddr)
{
	if(m_pRecvChannSrcAddr)
		delete m_pRecvChannSrcAddr;

	m_pRecvChannSrcAddr = pSrcAddr;
}

void CRecvChannAttrs::SetAllocatedAddr(CAllocatedAddress* pAllocatedAddr)
{
	if(m_pRecvAllocatedAddr)
		delete m_pRecvAllocatedAddr;
	m_pRecvAllocatedAddr = pAllocatedAddr;
}

void CRecvChannAttrs::SetPrototype(CProtocolType* pProtoType)
{
	if(m_pRecvProtoType)
		delete m_pRecvProtoType;
	m_pRecvProtoType = pProtoType;
}

void CRecvChannAttrs::SetSessionID(CSessionID* pRecvSessionID)
{
	if(m_pRecvSessionID)
		delete m_pRecvSessionID;
	m_pRecvSessionID = pRecvSessionID;
}

void CRecvChannAttrs::SetRecvChannID(CRecvChannelID* pChannID)
{
	if(m_pRecvChannID)
		delete m_pRecvChannID;
	m_pRecvChannID = pChannID;
}


CTransChannAttrs::CTransChannAttrs()
{
	m_pTransAllocatedAddr = 0;
	m_pTransSessionID = 0;
	m_pTransChannDestAddr = 0;
	m_pTransChannID = 0;
	m_pTransProtoType = 0;
}


CTransChannAttrs::CTransChannAttrs(CProtocolType* pProtoType, CTransmitChannelID* pChannID, 
									CAllocatedAddress* pAllocateAddr, CSessionID* pSessionID, 
									CChannDestAddress* pDestAddr)
{
	m_pTransProtoType = pProtoType;
	m_pTransChannID = pChannID;
	m_pTransAllocatedAddr = pAllocateAddr;
	m_pTransSessionID = pSessionID;
	m_pTransChannDestAddr = pDestAddr;
}

CTransChannAttrs::~CTransChannAttrs()
{
	Clear();
}

void CTransChannAttrs::Clear()
{	
	if(m_pTransAllocatedAddr)
	{
		delete m_pTransAllocatedAddr;
		m_pTransAllocatedAddr = 0;
	}
	if(m_pTransChannID)
	{
		delete m_pTransChannID;
		m_pTransChannID = 0;
	}
	if(m_pTransProtoType)
	{
		delete m_pTransProtoType;
		m_pTransProtoType = 0;
	}
	if(m_pTransSessionID)
	{
		delete m_pTransSessionID;
		m_pTransSessionID = 0;
	}
	if(m_pTransChannDestAddr)
	{
		delete m_pTransChannDestAddr;
		m_pTransChannDestAddr = 0;
	}
}

int CTransChannAttrs::Encode(unsigned char *pdata, int len)
{
	// test if all attrs are valid!
	if(!m_pTransProtoType || !m_pTransChannID || !m_pTransAllocatedAddr
		|| !m_pTransSessionID || !m_pTransChannDestAddr)
	{
		Clear();
		return 0;
	}

	int nRet = 0;
	unsigned char *p = pdata;

	// append prototype
	nRet = m_pTransProtoType->Encode(p, len);
	if(nRet <= 0)
		return 0;
	p += nRet;
	
	// allocated addr
	nRet = m_pTransChannID->Encode(p, len);
	if(nRet <=0)
		return 0;
	p += nRet;

	nRet = m_pTransAllocatedAddr->Encode(p, len);
	if(nRet <=0)
		return 0;
	p += nRet;

	nRet = m_pTransSessionID->Encode(p, len);
	if(nRet <=0)
		return 0;
	p += nRet;

	nRet = m_pTransChannDestAddr->Encode(p, len);
	if(nRet <=0)
		return 0;
	p += nRet;

	return (p-pdata);
}

int CTransChannAttrs::Decode(unsigned char *pdata,int len)
{
	Clear();
	
	unsigned char *p = pdata;
	int n = len, nRet = 0;
	uint16 nAttrType = ntohs(*(unsigned short *)p), nAttrLen;
	
	if(MS_ATTRIBUTE_PROTO_TYPE != nAttrType)
		return 0;

	m_pTransProtoType = new CProtocolType();
	nRet = m_pTransProtoType->Decode(pdata, len);
	if(nRet <= 0)
		return 0;
	n -= nRet;
	p += nRet;

	while(n > 0)
	{
		nAttrType = ntohs(*(unsigned short *)p);
		p+=2;
		n-=2;

		nAttrLen = ntohs(*(unsigned short *)p);
		p+=2;
		n-=2;

		if(nAttrLen%4 || nAttrLen > n)
			return 0;

		p-=4;
		n+=4;
		switch(nAttrType)
		{			
		case MS_ATTRIBUTE_TRANSMIT_CHANNEL_ID:
			{
				m_pTransChannID = new CTransmitChannelID;
				nRet = m_pTransChannID->Decode(p,n);
				if(nRet <= 0)
					return 0;

				p+=nRet;
				n-=nRet;
			}
			break;
		case MS_ATTRIBUTE_ADDRESS:
			{
				m_pTransAllocatedAddr = new CAllocatedAddress;
				nRet = m_pTransAllocatedAddr->Decode(p,n);
				if(nRet <= 0)
					return 0;
				
				p+=nRet;
				n-=nRet;
			}
			break;
		case MS_ATTRIBUTE_SESSION_ID:
			{
				m_pTransSessionID = new CSessionID;
				nRet = m_pTransSessionID->Decode(p,n);
				if(nRet <= 0)
					return 0;
				
				p +=nRet;
				n -=nRet;
			}
			break;
		case MS_ATTRIBUTE_DESTINATION_ADDRESS:
			{
				m_pTransChannDestAddr = new CChannDestAddress;
				nRet = m_pTransChannDestAddr->Decode(p,n);
				if(nRet <= 0)
					return 0;
				
				p+=nRet;
				n-=nRet;
			}
			break;
			
		default:
			{//
				//printf("error type\n");
				p+=(nAttrLen+4);
				n-=(nAttrLen+4);
			}
			break;
		}

		if(m_pTransProtoType && m_pTransChannID && m_pTransAllocatedAddr
		&& m_pTransSessionID && m_pTransChannDestAddr)
		{
			break;
		}
	}

	if(!m_pTransProtoType || !m_pTransChannID || !m_pTransAllocatedAddr
		|| !m_pTransSessionID || !m_pTransChannDestAddr)
	{
		Clear();
		return 0;
	}

	return (p-pdata);
}

void CTransChannAttrs::SetTransDestAddr(CChannDestAddress* pTransDestAddr)
{
	if(m_pTransChannDestAddr)
		delete m_pTransChannDestAddr;

	m_pTransChannDestAddr = pTransDestAddr;
}

void CTransChannAttrs::SetAllocatedAddr(CAllocatedAddress* pAllocatedAddr)
{
	if(m_pTransAllocatedAddr)
		delete m_pTransAllocatedAddr;
	m_pTransAllocatedAddr = pAllocatedAddr;
}

void CTransChannAttrs::SetPrototype(CProtocolType* pProtoType)
{
	if(m_pTransProtoType)
		delete m_pTransProtoType;
	m_pTransProtoType = pProtoType;
}

void CTransChannAttrs::SetSessionID(CSessionID* pTransID)
{
	if(m_pTransSessionID)
		delete m_pTransSessionID;
	m_pTransSessionID = pTransID;
}

void CTransChannAttrs::SetTransChannID(CTransmitChannelID* pTransChannID)
{
	if(m_pTransChannID)
		delete m_pTransChannID;
	m_pTransChannID = pTransChannID;
}

CRecvPortAttrs::CRecvPortAttrs()
{
	m_pProtoType = 0;
	m_pRecvPort = 0;
	m_pSessionID = 0;
	m_pSrcAddr = 0;	
	m_pRecvAddr = 0;
}

CRecvPortAttrs::CRecvPortAttrs(CProtocolType* pProtoType, 
							   CRecvPortID* pRecvPort, 
							   CAllocatedAddress* pRelayAddr,
							   CSessionID* pSessionID, 
							   CChannSrcAddress* pSrcAddr)
{
	m_pProtoType = pProtoType;
	m_pRecvPort = pRecvPort;
	m_pRecvAddr = pRelayAddr;
	m_pSessionID = pSessionID;
	m_pSrcAddr = pSrcAddr;	
}

CRecvPortAttrs::~CRecvPortAttrs()
{
	Clear();
}

void CRecvPortAttrs::Clear()
{
	if(m_pProtoType)
	{
		delete m_pProtoType;
		m_pProtoType = 0;
	}

	if(m_pRecvPort)
	{
		delete m_pRecvPort;
		m_pRecvPort = 0;
	}
	
	if(m_pRecvAddr)
	{
		delete m_pRecvAddr;
		m_pRecvAddr = 0;
	}

	if(m_pSessionID)
	{
		delete m_pSessionID;
		m_pSessionID = 0;
	}

	if(m_pSrcAddr)
	{
		delete m_pSrcAddr;
		m_pSrcAddr = 0;	
	}
}

// set functions list
void CRecvPortAttrs::SetPrototype(CProtocolType* pProtoType)
{
	if(m_pProtoType)
		delete m_pProtoType;

	m_pProtoType = pProtoType;
}

void CRecvPortAttrs::SetRecvPort(CRecvPortID* pPortID)
{
	if(m_pRecvPort)
		delete m_pRecvPort;
	m_pRecvPort = pPortID;
}

void CRecvPortAttrs::SetRecvSrcAddr(CChannSrcAddress* pSrcAddr)
{
	if(m_pSrcAddr)
		delete m_pSrcAddr;
	m_pSrcAddr = pSrcAddr;
}

void CRecvPortAttrs::SetRecvAddr(CAllocatedAddress* pRecvAddr)
{
	if(m_pRecvAddr)
		delete m_pRecvAddr;
	m_pRecvAddr = pRecvAddr;
}

void CRecvPortAttrs::SetSessionID(CSessionID* pRecvSessionID)
{
	if(m_pSessionID)
		delete m_pSessionID;
	m_pSessionID = pRecvSessionID;
}

int CRecvPortAttrs::Encode(unsigned char *pdata,int len)
{
	// test if all attrs are valid!
	if(!m_pProtoType || !m_pRecvPort
		|| !m_pRecvAddr || !m_pSessionID || !m_pSrcAddr)
	{
		Clear();
		return 0;
	}

	int nRet = 0;
	unsigned char *p = pdata;

	// append prototype
	nRet = m_pProtoType->Encode(p, len);
	if(nRet <= 0)
		return 0;
	p += nRet;
	
	// recv port
	nRet = m_pRecvPort->Encode(p, len);
	if(nRet <= 0)
		return 0;
	p += nRet;

	// relay address
	nRet = m_pRecvAddr->Encode(p, len);
	if(nRet <= 0)
		return 0;
	p += nRet;

	// session id
	nRet = m_pSessionID->Encode(p, len);
	if(nRet <= 0)
		return 0;
	p += nRet;

	// recv channel source address
	nRet = m_pSrcAddr->Encode(p, len);
	if(nRet <= 0)
		return 0;
	p += nRet;

	return (p-pdata);
}


int CRecvPortAttrs::Decode(unsigned char *pdata,int len)
{
	Clear();
	
	unsigned char *p = pdata;
	int n = len, nRet = 0;
	uint16 nAttrType = ntohs(*(unsigned short *)p), nAttrLen;
	
	if(MS_ATTRIBUTE_PROTO_TYPE != nAttrType)
		return 0;

	m_pProtoType = new CProtocolType();
	nRet = m_pProtoType->Decode(pdata, len);
	if(nRet <= 0)
		return 0;

	n -= nRet;

	while(n > 0)
	{
		nAttrType = ntohs(*(unsigned short *)p);
		p+=2;
		n-=2;

		nAttrLen = ntohs(*(unsigned short *)p);
		p+=2;
		n-=2;

		if(nAttrLen%4 || nAttrLen > n)
			return 0;

		p-=4;
		n+=4;
		switch(nAttrType)
		{			
		case MS_ATTRIBUTE_RECV_PORT_ID:
			{
				m_pRecvPort = new CRecvPortID;
				nRet = m_pRecvPort->Decode(p,n);
				if(nRet == -1)
					return 0;

				p+=nRet;
				n-=nRet;
			}
			break;
		case MS_ATTRIBUTE_ADDRESS:
			{
				m_pRecvAddr = new CAllocatedAddress();
				nRet = m_pRecvAddr->Decode(p,n);
				if(nRet <= 0)
					return 0;

				p+=nRet;
				n-=nRet;
			}
			break;
		case MS_ATTRIBUTE_SESSION_ID:
			{
				m_pSessionID = new CSessionID;
				nRet = m_pSessionID->Decode(p,n);
				if(nRet == -1)
					return 0;
				
				p +=nRet;
				n -=nRet;
			}
			break;
		case MS_ATTRIBUTE_SOURCE_ADDRESS:
			{
				m_pSrcAddr = new CChannSrcAddress;
				nRet = m_pSrcAddr->Decode(p,n);
				if(nRet == -1)
					return 0;
				
				p+=nRet;
				n-=nRet;
			}
			break;
			
		default:
			{//
				//printf("error type\n");
				p+=(nAttrLen+4);
				n-=(nAttrLen+4);
			}
			break;
		}

		if(m_pProtoType && m_pRecvPort
			&& m_pRecvAddr && m_pSessionID && m_pSrcAddr)
		{
			break;
		}
	}

	if(!m_pProtoType || !m_pRecvPort
		|| !m_pRecvAddr || !m_pSessionID || !m_pSrcAddr)
	{
		Clear();
		return 0;
	}

	return (p-pdata);
}

CTransmitPortAttrs::CTransmitPortAttrs()
{
	m_pProtoType = 0;
	m_pTransmitPort = 0;
	m_pTransmitAddr = 0;
	m_pSessionID = 0;
	m_pDestAddr = 0;	
}

CTransmitPortAttrs::CTransmitPortAttrs(CProtocolType* pProtoType, 
									   CTransmitPortID* pTransPort, 
									   CAllocatedAddress* pRelayAddr,
									   CSessionID* pSessionID, 
									   CChannDestAddress* pDestAddr)
{
	m_pProtoType = pProtoType;
	m_pTransmitPort = pTransPort;
	m_pTransmitAddr = pRelayAddr;
	m_pSessionID = pSessionID;
	m_pDestAddr = pDestAddr;	
}

CTransmitPortAttrs::~CTransmitPortAttrs()
{
	Clear();
}

void CTransmitPortAttrs::Clear()
{
	if(m_pProtoType)
	{
		delete m_pProtoType;
		m_pProtoType = 0;
	}

	if(m_pTransmitPort)
	{
		delete m_pTransmitPort;
		m_pTransmitPort = 0;
	}

	if(m_pTransmitAddr)
	{
		delete m_pTransmitAddr;
		m_pTransmitAddr = 0;
	}

	if(m_pSessionID)
	{
		delete m_pSessionID;
		m_pSessionID = 0;
	}

	if(m_pDestAddr)
	{
		delete m_pDestAddr;
		m_pDestAddr = 0;	
	}
}

// set functions list
void CTransmitPortAttrs::SetPrototype(CProtocolType* pProtoType)
{
	if(m_pProtoType)
		delete m_pProtoType;

	m_pProtoType = pProtoType;
}

void CTransmitPortAttrs::SetTransmitPort(CTransmitPortID* pPortID)
{
	if(m_pTransmitPort)
		delete m_pTransmitPort;
	m_pTransmitPort = pPortID;
}

void CTransmitPortAttrs::SetTransDestAddr(CChannDestAddress* pDestAddr)
{
	if(pDestAddr)
		delete pDestAddr;
	m_pDestAddr = pDestAddr;
}

void CTransmitPortAttrs::SetTransmitAddr(CAllocatedAddress* pTransAddr)
{
	if(m_pTransmitAddr)
		delete m_pTransmitAddr;
	m_pTransmitAddr = pTransAddr;
}

void CTransmitPortAttrs::SetSessionID(CSessionID* pTransmitSessionID)
{
	if(m_pSessionID)
		delete m_pSessionID;
	m_pSessionID = pTransmitSessionID;
}

int CTransmitPortAttrs::Encode(unsigned char *pdata,int len)
{
	// test if all attrs are valid!
	if(!m_pProtoType || !m_pTransmitPort
		|| !m_pTransmitAddr || !m_pSessionID || !m_pDestAddr)
	{
		Clear();
		return 0;
	}

	int nRet = 0;
	unsigned char *p = pdata;

	// append prototype
	nRet = m_pProtoType->Encode(p, len);
	if(nRet <= 0)
		return 0;
	p += nRet;
	
	// transmit port
	nRet = m_pTransmitPort->Encode(p, len);
	if(nRet <= 0)
		return 0;
	p += nRet;

	// relay address
	nRet = m_pTransmitAddr->Encode(p, len);
	if(nRet <= 0)
		return 0;
	p += nRet;

	// session id
	nRet = m_pSessionID->Encode(p, len);
	if(nRet <= 0)
		return 0;
	p += nRet;

	// recv channel source address
	nRet = m_pDestAddr->Encode(p, len);
	if(nRet <= 0)
		return 0;
	p += nRet;

	return (p-pdata);
}


int CTransmitPortAttrs::Decode(unsigned char *pdata,int len)
{
	Clear();
	
	unsigned char *p = pdata;
	int n = len, nRet = 0;
	uint16 nAttrType = ntohs(*(unsigned short *)p), nAttrLen;
	
	if(MS_ATTRIBUTE_PROTO_TYPE != nAttrType)
		return 0;

	m_pProtoType = new CProtocolType();
	nRet = m_pProtoType->Decode(pdata, len);
	if(nRet <= 0)
		return 0;
	
	n -= nRet;
	p += nRet;

	while(n > 0)
	{
		nAttrType = ntohs(*(unsigned short *)p);
		p+=2;
		n-=2;

		nAttrLen = ntohs(*(unsigned short *)p);
		p+=2;
		n-=2;

		if(nAttrLen%4 || nAttrLen > n)
			return 0;

		p-=4;
		n+=4;
		switch(nAttrType)
		{			
		case MS_ATTRIBUTE_TRANSMIT_PORT_ID:
			{
				m_pTransmitPort = new CTransmitPortID;
				nRet = m_pTransmitPort->Decode(p,n);
				if(nRet <= 0)
					return 0;

				p+=nRet;
				n-=nRet;
			}
			break;
		case MS_ATTRIBUTE_ADDRESS:
			{
				m_pTransmitAddr = new CAllocatedAddress();
				nRet = m_pTransmitAddr->Decode(p,n);
				if(nRet <= 0)
					return 0;

				p+=nRet;
				n-=nRet;
			}
			break;
		case MS_ATTRIBUTE_SESSION_ID:
			{
				m_pSessionID = new CSessionID;
				nRet = m_pSessionID->Decode(p,n);
				if(nRet == -1)
					return 0;
				
				p +=nRet;
				n -=nRet;
			}
			break;
		case MS_ATTRIBUTE_DESTINATION_ADDRESS:
			{
				m_pDestAddr = new CChannDestAddress;
				nRet = m_pDestAddr->Decode(p,n);
				if(nRet <= 0)
					return 0;
				
				p+=nRet;
				n-=nRet;
			}
			break;
			
		default:
			{//
				//printf("error type\n");
				p+=(nAttrLen+4);
				n-=(nAttrLen+4);
			}
			break;
		}

		if(m_pProtoType && m_pTransmitPort
			&& m_pTransmitAddr && m_pSessionID && m_pDestAddr)
		{
			break;
		}
	}

	if(!m_pProtoType || !m_pTransmitPort
		|| !m_pTransmitAddr || !m_pSessionID || !m_pDestAddr)
	{
		Clear();
		return 0;
	}

	return (p-pdata);
}

CChannAttrsPair::CChannAttrsPair()
{
	m_pRecvChannAttrs = 0;
	m_pTransChannAttrs = 0;
}

CChannAttrsPair::CChannAttrsPair(CRecvChannAttrs* pRecvChannAttrs, CTransChannAttrs* pTransChannAttrs)
: m_pTransChannAttrs(pTransChannAttrs), m_pRecvChannAttrs(pRecvChannAttrs)
{
}

CChannAttrsPair::~CChannAttrsPair()
{
	Clear();
}

void CChannAttrsPair::Clear()
{
	if(m_pTransChannAttrs)
	{
		delete m_pTransChannAttrs;
		m_pTransChannAttrs = 0;
	}
	if(m_pRecvChannAttrs)
	{
		delete m_pRecvChannAttrs;
		m_pRecvChannAttrs = 0;
	}
}

int CChannAttrsPair::Encode(unsigned char *pdata,int len)
{
	// test if one of attrs is valid!
	if(!m_pRecvChannAttrs && !m_pTransChannAttrs)
	{
		return 0;
	}

	int nRet = 0;
	unsigned char *p = pdata;

	// append recvchann if it has value
	if(m_pRecvChannAttrs)
	{
		nRet = m_pRecvChannAttrs->Encode(p, len);
		if(nRet <= 0)
			return 0;
		p += nRet;
	}
	// append transchann if it has value
	if(m_pTransChannAttrs)
	{
		nRet = m_pTransChannAttrs->Encode(p, len);
		if(nRet <= 0)
			return 0;
		p += nRet;
	}

	return (p-pdata);
}

int CChannAttrsPair::Decode(unsigned char *pdata,int len)
{
	Clear();
	
	unsigned char *p = pdata;
	int n = len, nRet = 0;
	
	// parse out recvchann first
	m_pRecvChannAttrs = new CRecvChannAttrs();
	nRet = m_pRecvChannAttrs->Decode(p, n);
	if(nRet <= 0)
	{
		delete m_pRecvChannAttrs;
		m_pRecvChannAttrs = 0;
	}
	else
	{
		p+=nRet;
		n-=nRet;
	}
	
	// parse out transchann
	m_pTransChannAttrs = new CTransChannAttrs();
	nRet = m_pTransChannAttrs->Decode(p, n);
	if(nRet <= 0)
	{
		delete m_pTransChannAttrs;
		m_pTransChannAttrs = 0;
	}
	else
	{
		p+=nRet;
		n-=nRet;
	}

	return (p-pdata);
}

void CChannAttrsPair::SetRecvChannAttrs(CRecvChannAttrs* pRecvChannAttrs)
{
	if(m_pRecvChannAttrs)
		delete m_pRecvChannAttrs;
	m_pRecvChannAttrs = pRecvChannAttrs;
}

void CChannAttrsPair::SetTransChannAttrs(CTransChannAttrs* pTransChannAttrs)
{
	if(m_pTransChannAttrs)
		delete m_pTransChannAttrs;

	m_pTransChannAttrs = pTransChannAttrs;
}

CPortAttrsPair::CPortAttrsPair()
{
	m_pRecvPortAttrs = 0;
	m_pTransPortAttrs = 0;
}

CPortAttrsPair::~CPortAttrsPair()
{
	if(m_pRecvPortAttrs)
		delete m_pRecvPortAttrs;
	if(m_pTransPortAttrs)
		delete m_pTransPortAttrs;
}

CPortAttrsPair::CPortAttrsPair(CRecvPortAttrs* pRecvPortAttrs, CTransmitPortAttrs* pTransPortAttrs)
: m_pRecvPortAttrs(pRecvPortAttrs), m_pTransPortAttrs(pTransPortAttrs)
{
}

void CPortAttrsPair::Clear()
{
	if(m_pRecvPortAttrs)
	{
		delete m_pRecvPortAttrs;
		m_pRecvPortAttrs = 0;
	}
	if(m_pTransPortAttrs)
	{
		delete m_pTransPortAttrs;
		m_pTransPortAttrs = 0;
	}
}

int CPortAttrsPair::Encode(unsigned char *pdata, int len)
{
	// test if all attrs are valid!
	if(!m_pRecvPortAttrs && !m_pTransPortAttrs)
	{
		Clear();
		return 0;
	}

	int nRet = 0;
	unsigned char *p = pdata;

	// append prototype
	if(m_pRecvPortAttrs)
	{
		nRet = m_pRecvPortAttrs->Encode(p, len);
		if(nRet < 0)
			nRet = 0;
		p += nRet;
	}
	if(m_pTransPortAttrs)
	{
		nRet = m_pTransPortAttrs->Encode(p, len);
		if(nRet < 0)
			nRet = 0;		// calc the pointer offset
		p += nRet;
	}

	return (p-pdata);
}

int CPortAttrsPair::Decode(unsigned char *pdata,int len)
{
	Clear();
	
	unsigned char *p = pdata;
	int n = len, nRet = 0;

	m_pRecvPortAttrs = new CRecvPortAttrs();
	if(m_pRecvPortAttrs)
	{
		nRet = m_pRecvPortAttrs->Decode(p, n);
		if(nRet > 0)
		{
			p += nRet;
			n -= nRet;
		}
		else
		{
			delete m_pRecvPortAttrs;
			m_pRecvPortAttrs = 0;
		}
	}
	
	m_pTransPortAttrs = new CTransmitPortAttrs();
	if(m_pTransPortAttrs)
	{
		nRet = m_pTransPortAttrs->Decode(p, n);
		if(nRet > 0)
		{
			p += nRet;
			n -= nRet;
		}
		else
		{
			delete m_pTransPortAttrs;
			m_pTransPortAttrs = 0;
		}
	}

	return (p-pdata);
}

void CPortAttrsPair::SetRecvPortAttrs(CRecvPortAttrs* pRecvPortAttrs)
{
	if(m_pRecvPortAttrs)
		delete m_pRecvPortAttrs;
	m_pRecvPortAttrs = pRecvPortAttrs;
}

void CPortAttrsPair::SetTransPortAttrs(CTransmitPortAttrs* pTransPortAttrs)
{
	if(m_pTransPortAttrs)
		delete m_pTransPortAttrs;
	m_pTransPortAttrs = pTransPortAttrs;
}

int CProtocolType::Encode(unsigned char *pdata,int len)
{
	if(len < m_nLength+4)
		return -1;

	int n = 0;
	unsigned char *p = pdata;
	*(unsigned short *)p = htons(m_nType);
	p+=2;
	n+=2;
	m_nLength = sizeof(long);
	*(unsigned short *)p = htons(m_nLength);
	p+=2;
	n+=2;
	*(unsigned long *)p = htonl(m_nProtoType);
	return m_nLength + 4;
}

int CProtocolType::Decode(unsigned char *pdata,int len)
{
	unsigned char *p = pdata;
	int n = 0;
	m_nType = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	m_nLength = ntohs(*(unsigned short *)p);
	p+=2;
	n+=2;
	if(m_nLength!=sizeof(m_nProtoType)
		|| len<ATTR_LEN(m_nLength))
		return -1;

	m_nProtoType = ntohl(*(unsigned long *)p);
	return m_nLength + 4;
}
#endif
